module main;
    
    `define MAX_WIDTH   500
    `define MAX_HEIGHT  500
    
    parameter [2*8:1] BMP_BF_TYPE = "BM";

    /* num to filename string: 7890->"7890.bmp" */
    function [8*50-1:0] getOutName(
        input [8*50-1:0] InName
    );
        getOutName = {InName, ".txt"};
    endfunction
    
    task tell_pos(
        input integer fd
    );
        //对fd操作会改变fd位置,如fseek, fread, fwrite
        $display("pos = %0d", $ftell(fd));
    endtask
    
    function [4:0] strlen(
        input [25*8-1:0] str
    );
    integer i;
    reg [4:0] len;
    begin   
        len = 0;
        for(i = 0; i < 25; i = i + 1)
        begin
            // $display("%x ", str[i*8 +: 8]);
            if(str[i*8 +: 8] != 8'h00)
                len = len + 1;
        end
        // $display("%d,", len);
        strlen = len;
    end
    endfunction
    
    function [31:0] width_4byte_align(
        input [31:0] width
    );
        width_4byte_align = ((width * 24) / 8 + 3) / 4 * 4;
    endfunction
    
    function [31:0] get_bmp_bfSize(
        input [31:0] width,
        input [31:0] height
    );
        get_bmp_bfSize = width_4byte_align(width) * height + 54 /* + 2 */;
    endfunction

    /*
        coe: bmp -> hex
        C语言数组，水平扫描，24位色，不勾选5个框，RGB/BGR,
    */
    
    task read_bmp_to_txt(
         input [8*50-1:0] fileInName
    );
        reg [7:0] bmp_head [54:1];
        reg [7:0] rgb_line_mem [`MAX_WIDTH:1];    //1行数据, b[] g[] r[] 
        
        reg [15:0] bmp_bfType;
        reg [31:0] bmp_bfSize;
        reg [31:0] bmp_bfOffBits;
        reg [31:0] bmp_width;
        reg [31:0] bmp_height;
        
        reg [31:0] bmp_bfSize_real;
        reg [31:0] width_align;
        reg [8*50-1:0] fileOutName;

        integer w, h;
        integer idx;
        integer fdIn, fdOut;
        integer isPS;

        begin
            //initial start
            w     = 0;
            h     = 0;
            fdIn  = 0;
            fdOut = 0;
            isPS  = 0;
            idx   = 0;
            fileOutName = getOutName(fileInName);   //fileInName.txt
            
            //initial end
            $display("input: %0s, output: %0s", fileInName, fileOutName);
            
            fdIn  = $fopen(fileInName, "rb");   //binary read
            fdOut = $fopen(fileOutName, "w+");  //txt write 
            
            // tell_pos(fdIn);    //0
            // tell_pos(fdOut);   //0
            
            if(!fdIn) begin
                $display("file open failed: %0s", fileInName);
                $stop(1);
            end
            if(!fdOut) begin
                $display("file create failed: %0s", fileOutName);
                $stop(1);
            end
            //读取 fdIn 起始54个字节，存储在bmp_head
            $fread(bmp_head, fdIn, , 54);
            // tell_pos(fdIn);      //54

            bmp_bfType = {bmp_head[1], bmp_head[2]};
            
            if(bmp_bfType == BMP_BF_TYPE)
                $display("bmp file type is correct!");
            else begin
                $display("bmp file type is error: %c %c", bmp_head[1], bmp_head[2]);
                $stop(1);
            end
            
            bmp_bfSize     = {bmp_head[6], bmp_head[5], bmp_head[4], bmp_head[3]};
            bmp_bfOffBits  = {bmp_head[14], bmp_head[13], bmp_head[12], bmp_head[11]};
            bmp_width      = {bmp_head[22], bmp_head[21], bmp_head[20], bmp_head[19]};
            bmp_height     = {bmp_head[26], bmp_head[25], bmp_head[24], bmp_head[23]};
            
            //4字节对齐之后的实际宽度的字节数
            bmp_bfSize_real = get_bmp_bfSize(bmp_width, bmp_height);

            
            //检查文件大小是否吻合
            if(bmp_bfSize == bmp_bfSize_real)
                isPS = 1;
            else if(bmp_bfSize == bmp_bfSize_real + 2)  //ps文件末尾多2个0
                isPS = 2;
            else 
                isPS = 0;
            
            if(isPS) begin
                $display("bmp_height:    %0d", bmp_height);
                $display("bmp_width:     %0d", bmp_width);
                $display("bmp_bfSize:    %0d", bmp_bfSize);
                $display("bmp_bfOffBits: %0d", bmp_bfOffBits);
                $display("bmp file bfSize is match: %0d == %0d", bmp_bfSize, bmp_bfSize_real);
                $display("bmp file type: %0d, (1=normal, 2:ps)", isPS);
            end
            else begin
                $display("bmp file bfSize not match: %0d != %0d", bmp_bfSize, bmp_bfSize_real);
                $stop(1);
            end
            
            //write bmp header info to out.txt
            $fwrite(fdOut, "%0s\n", fileInName);
            $fwrite(fdOut, "bmp_width    : %0d\n", bmp_width);
            $fwrite(fdOut, "bmp_height   : %0d\n", bmp_height);
            $fwrite(fdOut, "bmp_bfSize   : %0d\n", bmp_bfSize);
            $fwrite(fdOut, "bmp_bfOffBits: %0d\n\n", bmp_bfOffBits);
            $fwrite(fdOut, "bmp head: \n\n");
            
            for(idx = 1; idx <= 54; idx = idx + 1) begin
                $fwrite(fdOut, "%2x ", bmp_head[idx]);
                if(idx % 16 == 0)
                    $fwrite(fdOut, "\n");
            end
            
            //bmp 宽度超出处理范围
            if(bmp_height > `MAX_HEIGHT || bmp_width > `MAX_WIDTH) begin
                $fwrite(fdOut, "\n\nbmp file size exceed! width=%0d, height=%0d", bmp_width, bmp_height);
                $display("bmp file size exceed! width=%0d, height=%0d", bmp_width, bmp_height);
                $stop(1);
            end
            
            //read a line rgb data
            width_align = width_4byte_align(bmp_width);

            for(h = 1; h <= bmp_height; h = h + 1) begin
                // tell_pos(fdIn);
                //read 
                $fwrite(fdOut, "\n\n/* line: %0d B-G-R */\n", h);
                $fread(rgb_line_mem, fdIn, ,width_align);
                //write
                for(w = 1; w <= width_align; w = w + 1) begin
                    $fwrite(fdOut, "%2x", rgb_line_mem[w]);

                    if(w % 15 == 0)
                        $fwrite(fdOut, "\n");
                    else if(w % 3 == 0)
                        $fwrite(fdOut, "  ");
                    else 
                        $fwrite(fdOut, " ");
                end
            end
            
            if(isPS == 2)
                $fwrite(fdOut, "%2x %2x", 0, 0);
                        
            //close file in.bmp and out.bmp
            $fclose(fdIn);
            $fclose(fdOut);
        end
    endtask
    
    integer threshold;
    reg [50*8-1:0] OutName;
    
    initial begin
        $timeformat(-6, 2, " us", 10);
        // OutName = getOutName("./img/len_top.bmp");
        $display("outname: %0s", OutName);
        read_bmp_to_txt("./img/3200x2100.bmp");
        $stop(1);
    end
    
endmodule
